package video;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter;
import utils.PicUtils;

public class Video implements Serializable {

    private static final long serialVersionUID = 3960073332674427191l;
    public double duration;
    public double rate;
    public int ftp;
    public int finterval;
    public int height;
    public int width;
    public int wsize;
    public File videoFile;
    public List<Flash> flashs;
    int flag;

    static Java2DFrameConverter converter = new Java2DFrameConverter();

    public Video(File file) {
        videoFile = file;
        flashs = new ArrayList<Flash>();
        flag = 0;
        init(file.getPath());

    }

    public Video(String filepath) {
        try {
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filepath));
            Video video = (Video) ois.readObject();
            this.duration = video.duration;
            this.rate = video.rate;
            this.ftp = video.ftp;
            this.finterval = video.finterval;
            this.height = video.height;
            this.width = video.width;
            this.wsize = video.wsize;
            this.videoFile = video.videoFile;
            this.flashs = video.flashs;
            this.flag = video.flag;
            if (flag < ftp) {
                init(filepath);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public void save(String filepath) {
        try {
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filepath + ".video"));
            oos.writeObject(this);
            oos.close();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public void init(String filepath) {
        Frame frame = null;
        FFmpegFrameGrabber fFmpegFrameGrabber = new FFmpegFrameGrabber(videoFile);
        Tm.bufferList.clear();
        while (Tm.bufferList.size() < Tm.xcsl) {
            Tm.bufferList.add(new StringBuffer());
        }
        try {
            fFmpegFrameGrabber.start();
            ftp = fFmpegFrameGrabber.getLengthInFrames();
            rate = fFmpegFrameGrabber.getFrameRate();
            duration = ftp / rate;
            finterval = (int) (1000 / rate + 0.5);
            System.out.println("视频时长:" + duration + "秒");
            System.out.println("============运行渲染开始,对视频提帧,耗时较长请等待============");
            long startTime = System.currentTimeMillis();

            frame = fFmpegFrameGrabber.grabImage();
            BufferedImage bfImg = FrameToBufferedImage(frame);
            height = bfImg.getHeight();
            width = bfImg.getWidth();
            wsize = PicUtils.compressPic(bfImg, 100, 0.8, 1920, 1080).getWidth();
//            wsize = Flash.compressImage(bfImg).getWidth();
            //ftp=40;
            while (flag < ftp) {
                //获取帧
                frame = fFmpegFrameGrabber.grabImage();
                if (flag < flashs.size()) {
                    continue;
                }
                if (flag / 1000 > (flag - 1) / 1000) {
                    while (Tm.using > 0) {
                        Thread.sleep(1000);
                    }
                    this.save(filepath + new Date().getTime());
                }
                if (frame != null) {
                    while (Tm.using >= Tm.xcsl) {
                        System.out.println("已完成" + flashs.size() + "/" + ftp);
                        Thread.sleep(1000);
                    }
                    //获取系统处理器个数，作为线程池数量
                    int corePoolSize = Runtime.getRuntime().availableProcessors();
                    int maximumPoolSize = 32;
                    long keepAliveTime = 10;
                    TimeUnit unit = TimeUnit.SECONDS;
                    BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(2);
                    ThreadFactory threadFactory = new NameTreadFactory();
                    RejectedExecutionHandler handler = new MyIgnorePolicy();
                    ThreadPoolExecutor
                            executor =
                            new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit,
                                    workQueue, threadFactory, handler);
                    executor.prestartAllCoreThreads(); // 预启动所有核心线程
                    Tm task = new Tm(this, new Flash(FrameToBufferedImage(frame), flag));
                    executor.execute(task);
                    flag++;
                } else {
                    ftp--;
                }
                System.out.println("启动" + flag + "/" + ftp);
                System.gc();
            }

            while (flashs.size() < flag) {
                Thread.sleep(1000);
                System.out.println("已完成" + flashs.size() + "/" + flag);
            }
            flashs.sort((o1, o2) -> {
                int i1 = o1.id;
                int i2 = o2.id;
                if (i1 > i2) {
                    return 1;
                }
                if (i1 < i2) {
                    return -1;
                }
                return 0;
            });
            long endTime = System.currentTimeMillis();
            System.out.println("============运行结束,耗时"+ (endTime - startTime)/1000 +"秒============");
            fFmpegFrameGrabber.stop();

        } catch (IOException E) {
            E.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static BufferedImage FrameToBufferedImage(Frame frame) {
        //创建BufferedImage对象
        return converter.getBufferedImage(frame);
    }

    static class NameTreadFactory implements ThreadFactory {

        private final AtomicInteger mThreadNum = new AtomicInteger(1);

        @Override
        public Thread newThread(Runnable r) {
            Thread t = new Thread(r, "my-thread-" + mThreadNum.getAndIncrement());
//            System.out.println(t.getName() + " has been created");
            return t;
        }
    }

    public static class MyIgnorePolicy implements RejectedExecutionHandler {

        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            doLog(r, e);
        }

        private void doLog(Runnable r, ThreadPoolExecutor e) {
// 可做日志记录等
            System.err.println(r.toString() + " rejected");
//          System.out.println("completedTaskCount: " + e.getCompletedTaskCount());
        }
    }
}
